/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 * Description: util source file
 */

#include "util.h"
#include <dirent.h>
#include <vector>
#include <map>
using namespace std;


int g_switchFlagTWO = 0;
int g_switchFlag = 0;

void ClearSwitchFlag()
{
    g_switchFlag = 0;
    g_switchFlagTWO = 0;
}

int g_imageVideoFlag = 0; // only for ImageMbufVideoSender
void ResetImageVideoFlag()
{
    g_imageVideoFlag = 0;
}

void Yuv420p2nv12(const cv::Mat &yuv420p, cv::Mat &yuv420_nv12, int32_t width, int32_t height)
{
    auto resolution = width * height;
    for (int i = 0; i < resolution / half; i += half) {
        yuv420_nv12.data[resolution + i] = yuv420p.data[resolution + (i / half)];
        yuv420_nv12.data[resolution + i + 1] = yuv420p.data[resolution + resolution / resolutionSize + (i / half)];
    }
}

int32_t getFiles(std::string &path, std::vector<std::string> &files, std::string suffix)
{
    std::string suffixName = "." + suffix;
    DIR *dirp;
    dirent *dp;
    int32_t fileCnt = 0;
    dirp = opendir(path.c_str());
    if (dirp == NULL) {
        return 0;
    }
    while ((dp = readdir(dirp)) != NULL) {
        std::string curpath(path);
        if (path.back() != '/') {
            curpath += string("/") += dp->d_name;
        } else {
            curpath += dp->d_name;
        }
        if (dp->d_type == DT_REG) {
            if (std::string(strrchr(dp->d_name, '.')) == suffixName) {
                files.push_back(curpath);
                fileCnt++;
            }
        }
    }
    closedir(dirp);
    return fileCnt;
}

int32_t getFilesBySort(std::string &path, std::vector<std::string> &files, std::string suffix)
{
    std::string suffixName = "." + suffix;
    int32_t fileCnt = 0;
    dirent **name_list;
    int32_t count = scandir(path.c_str(), &name_list, NULL, alphasort);
    if (g_switchFlag == CNF1) {
        count = -1;
    }
    if (count < 0) {
        return 0;
    }
    for (int32_t i = 0; i < count; i++) {
        dirent *name = name_list[i];
        std::string curpath(path);
        if (path.back() != '/') {
            curpath += string("/") += name->d_name;
        } else {
            curpath += name->d_name;
        }
        if (std::string(strrchr(name->d_name, '.')) == suffixName) {
            files.push_back(curpath);
            fileCnt++;
        }
        free(name);
    }
    free(name_list);
    return fileCnt;
}

time_t convertTimeStr2TimeStamp(string timeStr)
{
    tm timeinfo;
    strptime(timeStr.c_str(), "%Y-%m-%d %H:%M:%S", &timeinfo);
    time_t timeStamp = mktime(&timeinfo);
    return timeStamp;
}

FuncTimeMeasure::FuncTimeMeasure(std::string &&descrip) : description(std::move(descrip))
{
    start = std::chrono::steady_clock::now();
}

FuncTimeMeasure::~FuncTimeMeasure()
{
    end = std::chrono::steady_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
}

std::string CurrentTimeAndDate()
{
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);
    std::stringstream ss;
    ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X");
    return ss.str();
}

void ConfigMangage::Parse()
{
    try {
        auto root = Adsfi::HafYaml(file).GetNode();
        if (g_switchFlag == CN1) {
            configs.clear();
        }
        for (auto it = root.begin(); it != root.end(); ++it) {
            Config conf;
            conf.dir = (*it)["dir"].as<string>();
            conf.instanceId = (*it)["instanceId"].as<int32_t>();
            conf.width = (*it)["width"].as<int32_t>();
            conf.height = (*it)["height"].as<int32_t>();
            configs.push_back(conf);
        }
    } catch (YAML::TypedBadConversion<int32_t> &e) {
        cout << "config file format error,please check config file! <int32_t>" << endl;
    } catch (YAML::TypedBadConversion<std::string> &e) {
        cout << "config file format error,please check config file! <string>" << endl;
    } catch (YAML::ParserException &e) {
        cout << "config file format error,please check config file! ParserException" << endl;
    }
}

std::vector<Config> ConfigMangage::GetConfig()
{
    return configs;
}

void ConfigMangage::Show()
{
    cout << endl << endl;
    cout << "Image sender Configs:" << endl;
    cout << "dir\tinstanceId\twidth\theight" << endl;
    for (auto &conf : configs) {
        cout << conf.dir << "\t" << conf.instanceId << "\t\t" << conf.width << "\t" << conf.height << "\t" << endl;
    }
    cout << endl << endl;
}

bool ConfigMangage::CheckConfig()
{
    // check if duplicatee id exists
    map<int, int> count;
    for (auto &conf : configs) {
        count[conf.instanceId]++;
        if (count[conf.instanceId] > 1) {
            return false;
        }
    }
    return true;
}
